#include <deviceParamOperater.h>

int deviceParamCalculateHeadInform(struct deviceParameterCommonHead *paramData, int paramTotalSize)
{
    if (!paramData)
    {
        logerror("");
        return -1;
    }
    paramData->paramSize = paramTotalSize - sizeof(struct deviceParameterCommonHead);
    paramData->paramCrc = calculateUint16CrcHash(((uint8_t *)paramData) + sizeof(struct deviceParameterCommonHead), paramData->paramSize);
    logdebug("%d,%d", paramData->paramSize, paramData->paramCrc);
    return 0;
}

int deviceParamOperateInit(struct deviceParameterOperate *parmOpt, deviceReadParamCall readfunc, deviceWriteParamCall writefunc,
                           paramConfigCallBack configfunc, struct deviceParameterCommonHead *setParam, int setParamAllSize)
{
    if (!(parmOpt && readfunc && writefunc && configfunc && setParam && setParamAllSize >= sizeof(struct deviceParameterCommonHead)))
    {
        logerror("");
        return -1;
    }
    memset(parmOpt, 0, sizeof(struct deviceParameterOperate));
    parmOpt->readcall = readfunc;
    parmOpt->writecall = writefunc;
    parmOpt->configcall = configfunc;
    parmOpt->paramdata = setParam;
    parmOpt->paramAllSize = setParamAllSize;
    return 0;
}

// run once at code begin.
int deviceParamReadFromHard(struct deviceParameterOperate *parmOpt)
{
    int tmpflag;
    uint16_t tmpcrc16;
    struct deviceParameterCommonHead *tmpParam;
    if (!(parmOpt && parmOpt->readcall && parmOpt->writecall && parmOpt->configcall && parmOpt->paramdata &&
          parmOpt->paramAllSize >= sizeof(struct deviceParameterCommonHead)))
    {
        logerror("");
        return -1;
    }
    tmpParam = parmOpt->paramdata;
    // if we add parameter, and hard have not this param, use defualt.
    parmOpt->configcall(tmpParam, NULL, DEVICE_PARAM_CONFIG_LEVEL_0);
    do
    {
        tmpflag = parmOpt->readcall(tmpParam, parmOpt->paramAllSize);
        if (tmpflag < 0)
        {
            logerror("");
            tmpflag = -1;
            break;
        }
        if (tmpParam->paramSize > parmOpt->paramAllSize - sizeof(struct deviceParameterCommonHead))
        {
            logerror("");
            tmpflag = -3;
            break;
        }
        tmpcrc16 = calculateUint16CrcHash(((uint8_t *)tmpParam) + sizeof(struct deviceParameterCommonHead), tmpParam->paramSize);
        if (tmpcrc16 != tmpParam->paramCrc)
        {
            logerror("%x,%x", tmpcrc16, tmpParam->paramCrc);
            tmpflag = -2;
            break;
        }
        // tmpNormalParam->paramSize < deviceParameterNormalDataSize. do nothing, new param use defualt and not save.
    } while (0);
    logdebug("read result: %d", tmpflag);
    if (tmpflag < 0)
    {
        parmOpt->configcall(tmpParam, NULL, DEVICE_PARAM_CONFIG_LEVEL_0);
    }
    // if(tmpNormalParam->paramSize < deviceParameterNormalDataSize)
    // {
    //     deviceParamWriteToHard(parmOpt);
    // }
    return tmpflag;
}

int deviceParamWriteToHard(struct deviceParameterOperate *parmOpt)
{
    int tmpflag;
    if (!(parmOpt && parmOpt->readcall && parmOpt->writecall && parmOpt->configcall && parmOpt->paramdata &&
          parmOpt->paramAllSize >= sizeof(struct deviceParameterCommonHead)))
    {
        logerror("");
        return -1;
    }
    deviceParamCalculateHeadInform(parmOpt->paramdata, parmOpt->paramAllSize - sizeof(struct deviceParameterCommonHead));
    tmpflag = parmOpt->writecall(parmOpt->paramdata, parmOpt->paramAllSize);
    if (tmpflag < 0)
    {
        logerror("");
        tmpflag = -2;
        return -1;
    }
    return 0;
}

int deviceParamResetAndSave(struct deviceParameterOperate *parmOpt, int configLevel)
{
    if (!(parmOpt && parmOpt->readcall && parmOpt->writecall && parmOpt->configcall && parmOpt->paramdata &&
          parmOpt->paramAllSize >= sizeof(struct deviceParameterCommonHead)))
    {
        logerror("");
        return -1;
    }
    parmOpt->configcall(parmOpt->paramdata, NULL, configLevel);
    return deviceParamWriteToHard(parmOpt);
}

int deviceParamOperateConfig(struct deviceParameterOperate *parmOpt, const void *inputParam, int configLevel)
{
    if (!(parmOpt && parmOpt->readcall && parmOpt->writecall && parmOpt->configcall && parmOpt->paramdata &&
          parmOpt->paramAllSize >= sizeof(struct deviceParameterCommonHead)))
    {
        logerror("");
        return -1;
    }
    return parmOpt->configcall(parmOpt->paramdata, inputParam, configLevel);
}

